package routers

import (
	"context"
	"errors"
	"fmt"
	"gameserver/messages"
	"gameserver/server"
	"gameserver/server/Login/internal"
	"gameserver/server/redisutil"
	"net/http"
	"time"

	"gitee.com/night-tc/gobige/common"
	"gitee.com/night-tc/gobige/global"
	"gitee.com/night-tc/gobige/logger"
	"github.com/gin-gonic/gin"
	"github.com/redis/go-redis/v9"
)

const (
	MAX_NICKNAME_LENGTH = 16 // 昵称最大长度
)

func GetRouter(isdebug bool) *gin.Engine {
	gin.DefaultWriter = logger.NewLoggerIO(logger.LogLevelDebug, logger.LogKey_GinHttp)
	gin.DefaultErrorWriter = logger.NewLoggerIO(logger.LogLevelError, logger.LogKey_GinHttp)
	if !isdebug {
		gin.SetMode(gin.ReleaseMode)
	}
	result := gin.New()
	result.Use(GinLogger, gin.Recovery())
	result.GET("ping", func(ctx *gin.Context) {
		ctx.JSON(http.StatusOK, gin.H{
			"Built":   global.Built,
			"Commit":  global.Gitcommit,
			"Version": global.Version,
		})
	})
	if isdebug {
		result.POST("debuglogin", DebugLogin_Handler)
	}
	ClientGroup := result.Group("loginAfter", loginAfter_Handler)
	ClientGroup.POST("getGroupList", GetGroupList_Handler) // 获取服务器列表
	ClientGroup.POST("createPlayer", CreatePlayer_Hander)  // 创建角色
	ClientGroup.POST("gameStart", GameStart_Handler)       // 开始游戏

	inner := result.Group("inner", innerAlfter_Handler)
	inner.POST("changename", ChangePlayerName_Handler)   // 修改角色名
	inner.POST("checklegalname", CheckLegalName_Handler) // 检查角色名是否合法
	inner.POST("upexdata", UpExData_Handler)             // 更新扩展数据

	GmAPI := result.Group("/GMAPI", innerAlfter_Handler) //使用一样的验证方式，有需要可以修改
	//白名单功能
	GmAPI.GET("whiteList", GetWhiteListGmHandler)             //GM获得 白名单列表
	GmAPI.POST("whiteList", SetOneWhiteListGmHandler)         //GM设置 插入一个白名单
	GmAPI.POST("whiteList/batch", SetBatchWhiteListGmHandler) //GM设置 插入多个白名单
	GmAPI.DELETE("whiteList", DeleteWhiteListGmHandler)       //GM删除 白名单

	return result
}

func GinLogger(c *gin.Context) {
	if !logger.CheckKey(logger.LogKey_GinHttp) {
		c.Next()
		return
	}

	// Start timer
	start := time.Now()
	path := c.Request.URL.Path
	raw := c.Request.URL.RawQuery
	// Process request
	c.Next()
	out := gin.DefaultWriter
	// Log only when path is not being skipped
	n := time.Now()
	tmp := n.Sub(start)
	if raw != "" {
		path = path + "?" + raw
	}
	log := fmt.Sprintf("| %3d | %15s |%s %s %#v\n%s",
		c.Writer.Status(),
		tmp,
		c.ClientIP(),
		c.Request.Method,
		path,
		c.Errors.ByType(1).String())
	_, _ = out.Write([]byte(log))
}

/*
设置角色登录GateSession信息
生成Token
*/
func SetRedisPlayerGateway(pmd *messages.Player_MD, umd *messages.Account_MD, gmd *messages.Group_MD) (outaddr, token string, reterr error) {
	gsrd := redisutil.NewGateSession(pmd.PlayerID)
	rd := gsrd.GetRedisF()
	reterr = rd.Watch(rd.Ctx, func(tx *redis.Tx) error {
		sessinfo, err := gsrd.GetInfo(tx)
		if err != nil && !errors.Is(err, redis.Nil) {
			return err
		}
		sid, _ := common.NewString(sessinfo[redisutil.GateSession_Key_Gateway]).ToUint64()
		sinfo, err := internal.GetSrvinst().GetDirMgr().GetServerById(uint32(pmd.GroupID), global.ServerTypeGateway, sid)
		if err != nil {
			sinfo, err = internal.GetSrvinst().GetDirMgr().GetServerByType(uint32(pmd.GroupID), global.ServerTypeGateway)
			if err != nil {
				return err
			}
		}
		nsessinfo := make(map[string]any)
		nsessinfo[redisutil.GateSession_Key_PlayerID] = common.NewStringAny(pmd.PlayerID).String()
		nsessinfo[redisutil.GateSession_Key_GroupID] = common.NewStringAny(pmd.GroupID).String()
		nsessinfo[redisutil.GateSession_Key_UserID] = common.NewStringAny(umd.UserID).String()
		nsessinfo[redisutil.GateSession_Key_OpenID] = common.NewStringAny(umd.OpenID).String()
		nsessinfo[redisutil.GateSession_Key_ChannelID] = common.NewStringAny(umd.ChannelID).String()

		outaddr = sinfo.GetListenAdd(global.ListenType_Outer)
		tstoken, ts := internal.CreateToken(pmd.PlayerID)
		token = tstoken
		nsessinfo[redisutil.GateSession_Key_Gateway] = common.NewStringAny(sinfo.GetServerID()).String()
		nsessinfo[redisutil.GateSession_Key_Addr] = outaddr
		nsessinfo[redisutil.GateSession_Key_Token] = tstoken
		nsessinfo[redisutil.GateSession_Key_Timestamp] = common.NewStringAny(ts).String()

		_, err = tx.TxPipelined(rd.Ctx, func(pipe redis.Pipeliner) error {
			return gsrd.SaveInfo(pipe, nsessinfo)
		})
		return err
	}, gsrd.GetKey())

	// 需要将老用户下线
	oncelg := redisutil.NewOnceLogin(umd.UserID)
	oldplayerid, _ := oncelg.GetSetPlayerID(pmd.PlayerID)
	if oldplayerid > 0 && oldplayerid != pmd.PlayerID {
		oldpmd := redisutil.NewLoginPlayer(oldplayerid)
		oldpmap, _ := oldpmd.GetInfo()
		if v, ok := oldpmap.Get(redisutil.LoginPlayer_Key_GroupID); ok {
			oldgid := v.ToUint64V()
			// 发送下线通知
			msg := new(messages.LogoutPlayerSrv)
			linker := internal.GetSrvinst().GetLinkerSrv(uint32(oldgid))
			_, err := linker.CallRouterSrvReqByPID(context.Background(), msg,
				oldplayerid, server.ServerType_Game)
			if err != nil {
				logger.Warnf("Failed to call LogoutPlayerSrv: %v", err)
			}
		}

	}

	return
}
